#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memalloc.h>
#include <gtest/gtest.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

TEST(MyFunctionTests, mem_init)
{
    extern errno;
    mem_init(1, 1, "swap.txt");
    mem_init(1, 1, "swap.txt");
    ASSERT_EQ(EALREADY, errno);
    mem_deinit();

    size_t size=(size_t)-1;
    mem_init(size, 2, "swap.txt");
    ASSERT_EQ(ENOMEM, errno);

    int fd=open("kaban.txt", O_RDWR|O_CREAT,0666);//we name the file kaban.txt as no user has such a file in his file system, so the new one will be created with privileges we need
    mem_init(4, 4, "kaban.txt");
    ASSERT_EQ(EBUSY, errno);
    close(fd);
    //should we do deinit here?

    mem_init (4, size, "swap.txt");
    ASSERT_EQ(ENOSPC, errno);
    //deinit?

    mem_init (4, 4, "kaban/swap.txt");
    ASSERT_EQ(ENOTDIR, errno);

    int fd=open("kaban.txt", O_WRONLY|O_CREAT, S_IWUSR);
    close(fd);
    mem_init(4, 4, "kaban.txt");
    ASSERT_EQ(EACCESS, errno);
   //deinit?

   //TODO: EFAULT, EFBIG, check that malloc has allocated memory

    mem_init(4, 4, "swap.txt");
    ASSERT_EQ (4, (fseek("swap.txt", 0, SEEK_SET)-fseek("swap.txt", 0, SEEK_END)));
    mem_deinit();

    //Should we do several tests for one issue?
    //use, for example, ASSERT_NE for more tests on one issue
}

TEST(MyFunctionTests, mem_change)
{
    extern errno;

    size_t size=(size_t)-1;
    mem_init(2, 2, "swap.txt");
    mem_realloc (size, 2, "swap.txt");
    ASSERT_EQ(ENOMEM, errno);
    mem_deinit;

    mem_init(4, 4, "swap.txt");
    int fd=open("kaban.txt", O_RDWR|O_CREAT,0666);
    mem_realloc(4, 4, "kaban.txt");
    ASSERT_EQ(EBUSY, errno);
    close(fd);
    mem_deinit();

    mem_init (4, 4, "swap.txt");
    mem_realloc(4, size, "swap.txt");
    ASSERT_EQ(ENOSPC, errno);
    mem_deinit();

    mem_init (4, 4, "swap.txt");
    mem_realloc (4, 4, "kaban/swap.txt");
    ASSERT_EQ(ENOTDIR, errno);
    mem_deinit();

    int fd=open("kaban.txt", O_WRONLY|O_CREAT, S_IWUSR);
    close(fd);
    mem_init(4, 4, "swap.txt");
    mem_realloc(4, 4, "kaban.txt");
    ASSERT_EQ (EACCESS, errno);
    mem_deinit();

    mem_init(4, 4, "swap.txt");
    mem_realloc(4, 8, "swap.txt");
    ASSERT_EQ (8, (fseek("swap.txt", 0, SEEK_SET)-fseek("swap.txt", 0, SEEK_END)));
    mem_deinit();

    mem_init(4, 4, "swap.txt");
    mem_realloc(4, NULL, "swap.txt");//should here be 0 or NULL?
    ASSERT_EQ (4, (fseek("swap.txt", 0, SEEK_SET)-fseek("swap.txt", 0, SEEK_END)));
    mem_deinit();

//TODO: EFAULT, EFBIG, check that malloc has allocated memory; in case NULL check
}

TEST(MyFunctionTests, mem_deinit)
{
    //TODO: check free
    mem_init(4, 4, "swap.txt");
    mem_deinit();
    ASSERT_EQ(EACCESS, open("swap.txt", O_RDWR));//we checked if the file was deleted
}

TEST(MyFunctionTests, mem_alloc)
{
    int i, j;

    mem_init(20, ULONG_MAX, "swap.txt");
    for (i=1; i<ULONG_MAX; i++) {
        ASSERT_LE(ULONG_MAX, mem_alloc(1));
        ASSERT_GE(0, mem_alloc(1));
    }
    mem_deinit();

    mem_init(20, 20, "swap.txt");
    ASSERT_EQ(0, mem_alloc(25));
    ASSERT_EQ(ENOMEM, errno);
    ASSERT_EQ(0, mem_alloc(41));
    ASSERT_EQ(E2BIG, errno);
    mem_deinit();

//TODO: EMLINK: how can we run out of valid ids? ULONG_MAX=4.294.967.295~4TB-that's too much for our computers
//the value of any 2 ids are not the same:
    mem_init(2000, 2000, "swap.txt");
    int* a=(int*)malloc(sizeof(int));
    for (i=0; i<1000; i++) {
        a[i]=mem_alloc(1);
        for (j=0; j<i; j++)
            ASSERT_NE(0, a[i]-a[j]);
    }
    //there is no use of doing i>1000: on our computers it's more than enough
    free(a);
    mem_deinit();
}

TEST(MyFunctionTests, mem_realloc)
{
//TODO:EMLINK
    mem_init(20, 20, "swap.txt");
    for (i=1; i<ULONG_MAX; i++)
        mem_alloc(1);
    int i;
    for (i=1; i<2*ULONG_MAX; i++) {
        ASSERT_LE(ULONG_MAX, mem_realloc(i, 2, 0));
        ASSERT_GE(0, mem_realloc(i, 2, 0));
    }
    mem_deinit();

    /*mem_init(20, 20, "swap.txt");
    mem_alloc(1);
    ASSERT_E(0, mem_realloc(1, 25, 0));
    ASSERT_E(ENOMEM, errno);
    ASSERT_E(0, mem_alloc(1 ,41, 0));
    ASSERT_E(E2BIG, errno);
    mem_deinit();*/

    size_t size=(size_t)-1;
    mem_init(20, 20, "swap.txt");
    mem_alloc(1);
    ASSERT_EQ(0,mem_realloc(1, size, 0));
    ASSERT_EQ(ENOMEM, errno);
    mem_deinit();

    mem_init(2000, 2000, "swap.txt");
    int* a=(int*)malloc(sizeof(int));
    for (i=0; i<1000; i++) {
        a[i]=mem_alloc(1);
    }
    for (i=0; i<1000; i++) {
        a[i]=mem_realloc(1, 2, 0);
        for (j=0; j<i; j++)
            ASSERT_NE(0, a[i]-a[j]);
    }
    //there is no use of doing i>1000: on our computers it's more than enough
    free(a);
    mem_deinit();

//TODO: what does busy/not busy mean? mode-? according to it do some additional tests
//TODO: what does "add the needed amount of bytes" mean?
}

TEST(MyFunctionTests, mem_free)
{
//no ideas how to do tests
}

TEST(MyFunctionTests, mem_get)
{
    mem_init(4, 4, "swap_path");
    mem_alloc(2);
    ASSERT_EQ(0, mem_get(1000));
    ASSERT_EQ(EFAULT, errno);
    mem_deinit();
    //TODO: ENOMEM, ENOBUFS, check sth else
}

TEST(MyFunctionTests, mem_release)
{
    //???
}

int main()
{
    return 0;
}
